<?php
# TOKEN
namespace app\server;

use Yii;

class Auth extends Server
{
    // 生成TOEKN
    static public function enToken($userId, $data = array())
    {
        // 获取配置项
        $systemInfo = parent::getSystem();
        $coreInfo = isset($systemInfo['core']) ? $systemInfo['core'] : [];
        // 允许同一个用户同时在线数量(默认1)
        $shareLogin = isset($coreInfo['share_login']) ? $coreInfo['share_login'] : 1;
        // redis存储数据键名前缀
        $redisPrefix = isset($coreInfo['redis_prefix']) ? $coreInfo['redis_prefix'] : 'easy';
        // token密钥
        $tokenKey = isset($coreInfo['token_key']) ? $coreInfo['token_key'] : 'token-easyApi-62300.!@#';

        // token的键名
        $tokenK = $redisPrefix . '_token_' . $userId;

        // redis实例
        $redis = Yii::$app->redis;

        // 判断当前用户token是否存在
        $llen = $redis->llen($tokenK);
        $llen = floor($llen);

        // 如果用户token存在并且达到登录上限
        if ($llen && $llen >= $shareLogin) {

            $deff = $llen - $shareLogin;
            // 剔除多余的token值
            for ($i = 0; $i <= $deff; $i++) {
                $redis->rpop($tokenK);
            }
        }

        // 生成唯一标识
        $unique = sha1(microtime(true) . uniqid(true) . mt_rand(10000000, 99999999));

        // 写入token
        $lpush = $redis->lpush($tokenK, $unique);

        // token有效期24小时
        # $redis->expire($tokenK, 86400);

        if ($lpush) {
            # AES加密用户数据
            $tokenData = $userId . '###' . json_encode($data);
            $tokenDataEn = Aes::encode($tokenData);

            // ( token密钥 + unique + 携带AES数据 ) 生成用户token信息
            $token = substr(sha1(sha1($tokenKey . $unique . $tokenDataEn)), 6, 30) . $tokenDataEn;
            return $token;
        }
    }

    // 验证TOEKN
    static public function deToken($token = '')
    {
        // 获取tokenData部分
        $tokenDataEn = substr($token, 30);
        $tokenData = Aes::decode($tokenDataEn);
        if (!$tokenData) {
            return false;
        }

        // 拆分tokenData
        $aesInfo = explode("###", $tokenData);
        if (count($aesInfo) != 2) {
            return false;
        }

        // 获取用户ID和携带AES数据
        $userId = $aesInfo[0];
        $userInfo = json_decode($aesInfo[1], true);
        if (!$userId) {
            return false;
        }

        // 获取配置项
        $systemInfo = parent::getSystem();
        $coreInfo = isset($systemInfo['core']) ? $systemInfo['core'] : [];
        // redis存储数据键名前缀
        $redisPrefix = isset($coreInfo['redis_prefix']) ? $coreInfo['redis_prefix'] : 'easy';
        // token密钥
        $tokenKey = isset($coreInfo['token_key']) ? $coreInfo['token_key'] : 'token-easyApi-62300.!@#';

        // token的键名
        $tokenK = $redisPrefix . '_token_' . $userId;
        // redis实例
        $redis = Yii::$app->redis;

        // 获取用户当前所有token
        $tokenAll = $redis->lrange($tokenK, 0, -1);

        // 查找是否有符合的身份信息存在
        foreach ($tokenAll as $val) {

            $unique = $val;
            $aesInfo = $userId . '###' . json_encode($userInfo);
            $aesInfoEn = Aes::encode($aesInfo);
            $makeToken = substr(sha1(sha1($tokenKey . $unique . $aesInfoEn)), 6, 30) . $aesInfoEn;
            // 比对TOKEN
            if ($token === $makeToken) {
                return $userInfo;
            }
        }
        return false;
    }

    // 验证签名
    static public function checkSign($data)
    {
        $sign = isset($data['sign']) ? $data['sign'] : '';
        $makeSign = self::makeSign($data);
        if (!$makeSign || $sign !== $makeSign) {
            return false;
        }
        return true;
    }

    // 生成签名
    static public function makeSign($data)
    {
        if (isset($data['sign'])) {
            unset($data['sign']);
        }
        if (empty($data)) {
            return false;
        }
        ksort($data);
        $sign = '';
        foreach ($data as $k => $val) {
            if (!empty($val)) {
                $sign .= $k . '=' . $val . '&';
            }
        }
        // 获取配置项
        $systemInfo = parent::getSystem();
        $coreInfo = isset($systemInfo['core']) ? $systemInfo['core'] : [];
        // 签名密钥
        $signKey = isset($coreInfo['sign_key']) ? $coreInfo['sign_key'] : '123456';
        $sign = trim($sign, '&') . $signKey;
        return strtolower(hash('sha256', $sign));
    }

}